package com.xique.door.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdcardUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xique.common.core.exception.BaseException;
import com.xique.common.core.text.Convert;
import com.xique.common.core.utils.DateUtils;
import com.xique.common.core.utils.MathUtil;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.door.bean.dao.AgeStatisticDAO;
import com.xique.door.bean.dao.DomicileStatisticDAO;
import com.xique.door.bean.domain.*;
import com.xique.door.bean.dto.UserBuildingInfoDTO;
import com.xique.door.bean.request.HouseSelectUserRequest;
import com.xique.door.bean.request.deviceUser.DeviceUserSelectListRequest;
import com.xique.door.bean.request.user.UserSelectRequest;
import com.xique.door.bean.search.user.UserListSearch;
import com.xique.door.bean.vo.user.UserListVo;
import com.xique.door.biz.service.IDeviceCommandNewService;
import com.xique.door.mapper.DCardMapper;
import com.xique.door.mapper.UserMapper;
import com.xique.door.mapper.UserMapperV1;
import com.xique.door.service.IAccessDeviceService;
import com.xique.door.service.IPermissionGroupDeviceService;
import com.xique.door.service.IPermissionGroupDomainService;
import com.xique.door.service.IUserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 门禁用户信息Service业务层处理
 *
 * @author caogq
 * @date 2021-06-10
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapperV1, UserV1> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserMapperV1 userMapperV1;

    @Autowired
    private IPermissionGroupDeviceService permissionGroupDeviceService;

    @Autowired
    private IAccessDeviceService accessDeviceService;

    @Autowired
    private IPermissionGroupDomainService permissionGroupDomainService;

    @Autowired
    private IDeviceCommandNewService deviceCommandNewService;

    @Autowired
    private DCardMapper dCardMapper;

    /**
     * 查询门禁用户信息
     *
     * @param id 门禁用户信息ID
     * @return 门禁用户信息
     */
    @Override
    public User selectUserById(Long id) {
        return userMapper.selectUserById(id);
    }

    @Override
    public List<User> selectUserByIds(List<Long> userIds) {
        return userMapper.selectUserByIds(userIds, null);
    }

    @Override
    public List<User> selectUserByIds(List<Long> userIds, Integer status) {
        if (userIds.isEmpty()) {
            return new ArrayList<>();
        }
        return userMapper.selectUserByIds(userIds, status);
    }

    /**
     * 查询门禁用户信息列表
     *
     * @param user 门禁用户信息
     * @return 门禁用户信息
     */
    @Override
    public List<User> selectUserList(User user) {
        return userMapper.selectUserList(user);
    }

    /**
     * 新增门禁用户信息
     *
     * @param user 门禁用户信息
     * @return 结果
     */
    @Override
    public int insertUser(User user) {
        user.setCreateTime(DateUtils.getNowDate());
        //32位id生成逻辑 = 13位时间戳+19位随机数
        String customId = System.currentTimeMillis() + MathUtil.getRandom(19);
        user.setCustomId(customId);
        user.setVisitorType("0");
        user.setType(user.getIdentityType());
        if(user.getCreateUser()==null){
            user.setCreateUser(SecurityUtils.getUserId());
        }
        user.setUpdateUser(user.getCreateUser());
        user.setCreateTime(new Date());
        user.setUpdateTime(user.getCreateTime());
        return userMapper.insertUser(user);
    }

    /**
     * 修改门禁用户信息
     *
     * @param user 门禁用户信息
     * @return 结果
     */
    @Override
    public AjaxResult updateUser(User user) {

        user.setUpdateTime(DateUtils.getNowDate());
        if (user.getUpdateUser() == null) {
            user.setUpdateUser(SecurityUtils.getUserId());
        }
        int rows = userMapper.updateUser(user);
        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * 删除门禁用户信息对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteUserByIds(String ids) {
        return userMapper.deleteUserByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除门禁用户信息信息
     *
     * @param id 门禁用户信息ID
     * @return 结果
     */
    @Override
    public int deleteUserById(Long id) {
        return userMapper.deleteUserById(id);
    }

    @Override
    public int clearUserUrl(String id) {
        return userMapper.clearUserUrl(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String importUser(Long parkId, List<User> userList, boolean updateSupport) {

        //初始化成功、失败消息及消息编号
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        User userSearch = new User();
        userSearch.setParkId(parkId);
        List<User> parkUserList = userMapper.selectUserList(userSearch);
        List<User> newUserList = new ArrayList<>();
        int number = 0;
        for (User user : userList) {
            number++;
            if (StringUtils.isEmpty(user.getUserName())) {
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、" + "第" + number + "个用户姓名为空!");
                break;
            }
            if (StringUtils.isNotEmpty(user.getIdCard()) && !IdcardUtil.isValidCard(user.getIdCard())) {
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、" + "第" + number + "个用户身份证号码不合法");
                break;
            }
//            if (StringUtils.isNotEmpty(user.getPhone()) && !PhoneUtil.isMobile(user.getPhone())) {
            //jrwu导入用户手机号，弱校验，11位纯数字
            if (StringUtils.isNotEmpty(user.getPhone()) && !user.getPhone().matches("^\\d{11}$")) {
                //校验手机号是否合理
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、" + "第" + number + "个用户手机号码不合法");
                break;
            }
            //去除\t
            user.setUserName(user.getUserName().replaceAll("\t", ""));
            user.setParkId(parkId);
            user.setVisitorType("0");
            user.setStatus("1");
            user.setPersonType(0);
            //32位id生成逻辑 = 13位时间戳+19位随机数
            String customId = System.currentTimeMillis() + MathUtil.getRandom(19);
            user.setCustomId(customId);
            Long currentUserId = SecurityUtils.getUserId();
            user.setCreateUser(currentUserId);
            user.setUpdateUser(currentUserId);
            user.setUpdateTime(new Date());
            if (StringUtils.isEmpty(user.getPhone())) {
                //如果用户手机号码为空，无法判断新增还是更新，都新增
                newUserList.add(user);
                successNum++;
                successMsg.append("<br/>" + successNum + "、用户【" + user.getUserName() + "-" + user.getPhone() + "】 导入成功");
            } else {
                //---------------------------------------------校验用户更新start-----------------------------------------------------
                //定义flag：用户是否存在
                Boolean existFlag = false;
                String userId = getUserIdByPhone(parkUserList, user.getPhone());
                if (StringUtils.isNotEmpty(userId)) {
                    existFlag = true;
                    user.setId(Long.valueOf(userId));
                }

                if (existFlag) {
                    if (updateSupport) {
                        //1、用户已存在，并支持更新
                        newUserList.add(user);
                        successNum++;
                        successMsg.append("<br/>" + successNum + "、用户【" + user.getUserName() + "-" + user.getPhone() + "】 更新成功");
                    } else {
                        //2、用户已存在，但不支持更新
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、用户【" + user.getUserName() + "-" + user.getPhone() + "】 手机号已存在，不支持更新操作");
                    }
                } else {
                    //3、用户不存在，直接新增
                    newUserList.add(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、用户【" + user.getUserName() + "-" + user.getPhone() + "】 导入成功");
                }
            }
            //---------------------------------------------校验用户更新end-----------------------------------------------------
        }

        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，部分数据校验失败！共 " + failureNum + " 条数据校验失败，错误如下：");
            throw new BaseException(failureMsg.toString());
        } else {
            //批量执行插入/更新操作
            if (CollectionUtils.isNotEmpty(newUserList)) {
                userMapper.batchInsetUser(newUserList);
            }
            //卡片数据插入
            List<DCard> dCardList = getDcardListFromUserList(newUserList);
            if (CollectionUtils.isNotEmpty(dCardList)) {
                dCardMapper.batchInsetDCard(dCardList);
            }
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    private String getUserIdByPhone(List<User> parkUserList, String phone) {
        if (CollectionUtils.isEmpty(parkUserList)) {
            return null;
        }
        for (User parkUser : parkUserList) {
            if (phone.equals(parkUser.getPhone())) {
                return String.valueOf(parkUser.getId());
            }
        }
        return null;
    }

    /**
     * 提取用户中的卡片信息，组成list
     * 判断是新增还是修改
     *
     * @param userList
     * @return
     */
    private List<DCard> getDcardListFromUserList(List<User> userList) {
        List<DCard> dCardList = new ArrayList<>(userList.size());
        DCard dCard;
        DCard select;
        List<DCard> dCardList1;
        for (User user : userList) {
            if (StringUtils.isNotEmpty(user.getCardSn())) {
                dCard = new DCard();
                select = new DCard();
                select.setUserId(user.getId());
                dCardList1 = dCardMapper.selectDCardList(select);
                if (CollectionUtils.isNotEmpty(dCardList1)) {
                    dCard.setId(dCardList1.get(0).getId());
                }
                dCard.setParkId(user.getParkId());
                dCard.setUserId(user.getId());
                String customId = System.currentTimeMillis() + MathUtil.getRandom(19);
                dCard.setCustomId(customId);
                dCard.setCardExternalNo(user.getCardExternalNo());
                dCard.setCardSn(user.getCardSn());
                dCard.setDoorBeginDate(user.getDoorBeginDate());
                dCard.setDoorEndDate(user.getDoorEndDate());
                dCard.setElevatorBeginDate(user.getElevatorBeginDate());
                dCard.setElevatorEndDate(user.getElevatorEndDate());
                dCard.setStatus(user.getStatus());
                dCard.setCreateUser(user.getCreateUser());
                dCard.setUpdateUser(user.getUpdateUser());
                dCard.setCreateTime(user.getCreateTime());
                dCard.setUpdateTime(user.getUpdateTime());
                dCardList.add(dCard);
            }
        }
        return dCardList;
    }

    @Override
    public int batchInsetUser(List<User> newUserList) {
        return userMapper.batchInsetUser(newUserList);
    }

    @Override
    public List<ParkInfo> selectParkInfoByUserPhone(String phone) {
        return userMapper.selectParkInfoByUserPhone(phone);
    }

    /**
     * 单用户绑定多权限组
     *
     * @param user
     * @param groups
     * @return
     */
    @Override
    public AjaxResult bindUserAndGroups(User user, List<String> groups, String type, Boolean personUpdateNeedSyncHk) {
        if (CollectionUtils.isEmpty(groups) || Objects.isNull(groups)) {
            return AjaxResult.error();
        }
        //1、维护用户和权限组关联表
        List<PermissionGroupUser> permissionGroupUsers = new ArrayList<>();
        groups.forEach(group -> {
            PermissionGroupUser permissionGroupUser = new PermissionGroupUser();
            permissionGroupUser.setUserId(user.getId());
            permissionGroupUser.setGroupId(Long.valueOf(group));
            permissionGroupUsers.add(permissionGroupUser);
        });

        //2、维护用户和设备关联表
        List<PermissionGroupDevice> groupDeviceList = permissionGroupDeviceService.selectPermissionGroupDeviceListByGroupIds(groups.stream().map(group -> Long.parseLong(group)).collect(Collectors.toList()));

        List<UserDevice> userDevices = new ArrayList<>();
        for (PermissionGroupDevice permissionGroupDevice : groupDeviceList) {
            AccessDevice accessDevice = accessDeviceService.selectAccessDeviceById(permissionGroupDevice.getDeviceId());
            if (!"normal".equals(accessDevice.getStatus())) {
                continue;
            }
            UserDevice userDevice = new UserDevice();
            userDevice.setParkId(user.getParkId());
            userDevice.setGroupId(permissionGroupDevice.getGroupId());
            userDevice.setUserId(user.getId());
            userDevice.setDeviceId(permissionGroupDevice.getDeviceId());
            userDevice.setDevSn(accessDevice.getDevSn());
            userDevices.add(userDevice);
        }

        int count = permissionGroupDomainService.selectUser(permissionGroupUsers, userDevices);
        if (count <= 0) {
            return AjaxResult.error();
        }
        //3、获取用户设备序号集合，下发到设备
        if (StringUtils.isNotEmpty(user.getFaceUrl())) {
            AjaxResult result = deviceCommandNewService.addUpdatePersionCommand(user, type, personUpdateNeedSyncHk);
            if (AjaxResult.isError(result)) {
                return result;
            }
        }
        return AjaxResult.success();

    }

    @Override
    public List<DomicileStatisticDAO> selectUserDomicileStatisticByProvince(Long parkId) {
        return userMapper.selectUserDomicileStatisticByProvince(parkId);
    }

    @Override
    public List<AgeStatisticDAO> selectUserAgeStatistic(Long parkId) {
        return userMapper.selectUserAgeStatistic(parkId);
    }

    @Override
    public List<User> selectUserByBaseUserId(Long id) {
        return userMapper.selectUserByBaseUserId(id);
    }

    @Override
    public List<User> houseSelectUsers(HouseSelectUserRequest request) {
        return userMapper.houseSelectUsers(request);
    }

    /**
     * @param request
     * @description: 用户列表查询
     * @author caogq
     * @date: 2022/1/25 17:15
     */
    @Override
    public List<UserListVo> selectConditionUserList(UserSelectRequest request) {
        return userMapper.selectConditionUserList(request);
    }

    @Override
    public List<UserListVo> selectUnAssignedDeviceUserList(DeviceUserSelectListRequest request) {
        return userMapper.selectUnAssignedDeviceUserList(request);
    }

    @Override
    public List<UserListVo> selectAssignedDeviceUserList(DeviceUserSelectListRequest request) {
        return userMapper.selectAssignedDeviceUserList(request);
    }

    @Override
    public List<User> selectUserByCustomIds(List<String> customIds) {
        return userMapper.selectUserByCustomIds(customIds);
    }

    @Override
//    @Cacheable(key = "#userId+'-'+#houseId+'-'+#buildingId+'-'+#areaId", value = "userBuildingInfoDTO")
    public UserBuildingInfoDTO selectUserBuildInfo(Long userId, Long houseId, Long buildingId, Long areaId) {
        UserBuildingInfoDTO dto = userMapper.selectUserBuildInfo(userId, houseId, buildingId, areaId);
        if (StringUtils.isNull(dto)) {
            UserV1 user = userMapperV1.selectById(userId);
            dto = new UserBuildingInfoDTO();
            dto.setUserId(user.getId());
            dto.setUserName(user.getUserName());
        }
        return dto;
    }

    @Override
    public IPage<UserV1> selectUserPageV1(UserListSearch search) {

        QueryWrapper<UserV1> condition = new QueryWrapper<>();
        if (StringUtils.isNotNull(search.getParkId())) {
            condition.eq("park_id", search.getParkId());
        }
        Page<UserV1> page = new Page<>();
        if (StringUtils.isNotNull(search.getPageNum()) && StringUtils.isNotNull(search.getPageSize())) {
            page.setCurrent(search.getPageNum());
            page.setSize(search.getPageSize());
        }
        condition.orderByDesc("create_time");
        return userMapperV1.selectPage(page, condition);
    }

    @Override
    public List<UserV1> selectUserListV1(UserListSearch search) {
        QueryWrapper<UserV1> condition = new QueryWrapper<>();
        if (StringUtils.isNotNull(search.getParkId())) {
            condition.eq("park_id", search.getParkId());
        }
        if (CollectionUtil.isNotEmpty(search.getParkIds())) {
            condition.in("park_id", search.getParkIds());
        }
        if (StringUtils.isNotNull(search.getBaseUserId())) {
            condition.eq("base_user_id", search.getBaseUserId());
        }
        condition.orderByDesc("create_time");
        return userMapperV1.selectList(condition);
    }

    @Override
    public UserV1 selectUserV1(UserV1 userV1) {
        QueryWrapper<UserV1> condition = new QueryWrapper<>();
        if (StringUtils.isNotNull(userV1.getParkId())) {
            condition.eq("park_id", userV1.getParkId());
        }
        if (StringUtils.isNotNull(userV1.getPhone())) {
            condition.eq("phone", userV1.getPhone());
        }
        if (StringUtils.isNotNull(userV1.getUserName())) {
            condition.eq("user_name", userV1.getUserName());
        }
        if (StringUtils.isNotNull(userV1.getBaseUserId())) {
            condition.eq("base_user_id", userV1.getBaseUserId());
        }
        condition.eq("del_flag", '0');
        return userMapperV1.selectOne(condition);
    }

    @Override
    public List<UserV1> selectUserListWithBaseInfo(UserListSearch search) {
        return userMapper.selectUserListWithBaseInfo(search);
    }

    @Override
    public boolean checkInvitationCode(Long parkId, String code) {
        int count = userMapper.checkInvitationCode(parkId, code);
        if (count >= 1) {
            return true;
        }
        return false;
    }

    @Override
    public UserV1 seleceteUserV(Long baseUserId, Long parkId, Long houseId) {
        return userMapper.seleceteUserV(baseUserId, parkId, houseId);
    }

    @Override
    public List<User> selectUserListWithoutBaseUser() {
        return userMapper.selectUserListWithoutBaseUser();
    }
}
